home *** CD-ROM | disk | FTP | other *** search
/ Amiga Plus 1995 #5 & #6 / Amiga Plus CD - 1995 - No. 5 and 6.iso / pd / daten / astrolog / src / xdevice.c < prev    next >
C/C++ Source or Header  |  1995-08-11  |  21KB  |  788 lines

  1. /*                                                               -*- C -*-
  2. ** Astrolog (Version 4.40) File: xdevice.c
  3. **
  4. ** IMPORTANT NOTICE: The graphics database and chart display routines
  5. ** used in this program are Copyright (C) 1991-1995 by Walter D. Pullen
  6. ** (astara@u.washington.edu). Permission is granted to freely use and
  7. ** distribute these routines provided one doesn't sell, restrict, or
  8. ** profit from them in any way. Modification is allowed provided these
  9. ** notices remain with any altered or edited versions of the program.
  10. **
  11. ** The main planetary calculation routines used in this program have
  12. ** been Copyrighted and the core of this program is basically a
  13. ** conversion to C of the routines created by James Neely as listed in
  14. ** Michael Erlewine's 'Manual of Computer Programming for Astrologers',
  15. ** available from Matrix Software. The copyright gives us permission to
  16. ** use the routines for personal use but not to sell them or profit from
  17. ** them in any way.
  18. **
  19. ** The PostScript code within the core graphics routines are programmed
  20. ** and Copyright (C) 1992-1993 by Brian D. Willoughby
  21. ** (brianw@sounds.wa.com). Conditions are identical to those above.
  22. **
  23. ** The extended accurate ephemeris databases and formulas are from the
  24. ** calculation routines in the program "Placalc" and are programmed and
  25. ** Copyright (C) 1989,1991,1993 by Astrodienst AG and Alois Treindl
  26. ** (alois@azur.ch). The use of that source code is subject to
  27. ** regulations made by Astrodienst Zurich, and the code is not in the
  28. ** public domain. This copyright notice must not be changed or removed
  29. ** by any user of this program.
  30. **
  31. ** Initial programming 8/28,30, 9/10,13,16,20,23, 10/3,6,7, 11/7,10,21/1991.
  32. ** X Window graphics initially programmed 10/23-29/1991.
  33. ** PostScript graphics initially programmed 11/29-30/1992.
  34. ** Last code change made 1/29/1995.
  35. */
  36.  
  37. /* $VER: $Id: xdevice.c,v 1.2 1995/07/02 22:22:49 tf Exp $ */
  38.  
  39. #include "astrolog.h"
  40.  
  41.  
  42. #ifdef GRAPH
  43. /*
  44. ******************************************************************************
  45. ** Bitmap File Routines.
  46. ******************************************************************************
  47. */
  48.  
  49. /* Write the bitmap array to a previously opened file in a format that   */
  50. /* can be read in by the Unix X commands bitmap and xsetroot. The 'mode' */
  51. /* parameter defines how much white space is put in the file.            */
  52.  
  53. void WriteXBitmap(file, name, mode)
  54. FILE *file;
  55. char *name, mode;
  56. {
  57.   int x, y, i, temp = 0;
  58.   _int value;
  59.  
  60.   fprintf(file, "#define %s_width %d\n" , name, gs.xWin);
  61.   fprintf(file, "#define %s_height %d\n", name, gs.yWin);
  62.  
  63.   fprintf(file, "static %s %s_bits[] = {", mode != 'V' ? "char" : "short", name);
  64.  
  65.   for (y = 0; y < gs.yWin; y++) 
  66.   {
  67.     x = 0;
  68.  
  69.     do {
  70.  
  71.       /* Process each row, eight columns at a time. */
  72.  
  73.       if (y + x > 0)
  74.         fprintf(file, ",");
  75.  
  76.       if (temp == 0)
  77.         fprintf(file, "\n%s", mode == 'N' ? "  " : (mode == 'C' ? " " : ""));
  78.  
  79.       value = 0;
  80.  
  81.       for (i = (mode != 'V' ? 7 : 15); i >= 0; i--)
  82.         value = (value << 1) + (!(FBmGet(gi.bm, x+i, y)^(gs.fInverse*15))^gs.fInverse && (x + i < gs.xWin));
  83.  
  84.       if (mode == 'N')
  85.         putc(' ', file);
  86.  
  87.       fprintf(file, "0x");
  88.  
  89.       if (mode == 'V')
  90.         fprintf(file, "%c%c", ChHex(value >> 12), ChHex((value >> 8) & 15));
  91.  
  92.       fprintf(file, "%c%c", ChHex((value >> 4) & 15), ChHex(value & 15));
  93.       temp++;
  94.  
  95.       /* Is it time to skip to the next line while writing the file yet? */
  96.  
  97.       if ((mode == 'N' && temp >= 12) ||
  98.           (mode == 'C' && temp >= 15) ||
  99.           (mode == 'V' && temp >= 11))
  100.         temp = 0;
  101.  
  102.       x += (mode != 'V' ? 8 : 16);
  103.  
  104.     } while (x < gs.xWin);
  105.   }
  106.   fprintf(file, "};\n");
  107. }
  108.  
  109.  
  110. /* Write the bitmap array to a previously opened file in a simple boolean    */
  111. /* Ascii rectangle, one char per pixel, where '#' represents an off bit and  */
  112. /* '-' an on bit. The output format is identical to the format generated by  */
  113. /* the Unix bmtoa command, and it can be converted into a bitmap with atobm. */
  114.  
  115. void WriteAscii(file)
  116. FILE *file;
  117. {
  118.   int x, y, i;
  119.  
  120.   for (y = 0; y < gs.yWin; y++) 
  121.   {
  122.     for (x = 0; x < gs.xWin; x++) 
  123.     {
  124.       i = FBmGet(gi.bm, x, y);
  125.       if (gs.fColor)
  126.         putc(ChHex(i), file);
  127.       else
  128.         putc(i ? '-' : '#', file);
  129.     }
  130.     putc('\n', file);
  131.   }
  132. }
  133.  
  134.  
  135. /* Write the bitmap array to a previously opened file in the bitmap format  */
  136. /* used in Microsoft Windows for its .bmp extension files. This is a pretty */
  137. /* efficient format, only requiring a small header, and one bit per pixel   */
  138. /* for monochrome graphics, or four bits per pixel for full color.          */
  139.  
  140. void WriteBmp(file)
  141. FILE *file;
  142. {
  143.   int x, y;
  144.   dword value;
  145.  
  146.   /* Note that we sometimes only write a part of the full bitmap to disk   */
  147.   /* during the call, as done when the bitmap is being generated in bands. */
  148.  
  149.   if (gi.yBand == 0 || gi.yOffset + gi.yBand >= gs.yWin)
  150.   {
  151.     /* BitmapFileHeader */
  152.  
  153.     PutByte('B'); PutByte('M');
  154.     PutLong(14+40 + (gs.fColor ? 64 : 8) + (long)4*gs.yWin*((gs.xWin-1 >> (gs.fColor ? 3 : 5))+1));
  155.     PutWord(0); PutWord(0);
  156.     PutLong(14+40 + (gs.fColor ? 64 : 8));
  157.  
  158.     /* BitmapInfo / BitmapInfoHeader */
  159.  
  160.     PutLong(40);
  161.     PutLong(gs.xWin); PutLong(gs.yWin);
  162.     PutWord(1); PutWord(gs.fColor ? 4 : 1);
  163.     PutLong(0 /*BI_RGB*/); PutLong(0);
  164.     PutLong(0); PutLong(0);
  165.     PutLong(0); PutLong(0);
  166.  
  167.     /* RgbQuad */
  168.  
  169.     if (gs.fColor)
  170.     {
  171.       for (x = 0; x < 16; x++)
  172.       {
  173.         PutByte(RGBB(rgbbmp[x])); PutByte(RGBG(rgbbmp[x]));
  174.         PutByte(RGBR(rgbbmp[x])); PutByte(0);
  175.       }
  176.     }
  177.     else
  178.     {
  179.       PutLong(0);
  180.       PutByte(255); PutByte(255); PutByte(255); PutByte(0);
  181.     }
  182.   }
  183.  
  184.   /* Data */
  185.  
  186.   for (y = (gi.yBand ? Min(gi.yBand, gs.yWin - gi.yOffset) : gs.yWin) - 1; y >= 0; y--) 
  187.   {
  188.     value = 0;
  189.  
  190.     for (x = 0; x < gs.xWin; x++) 
  191.     {
  192.       if ((x & (gs.fColor ? 7 : 31)) == 0 && x > 0) 
  193.       {
  194.         PutLong(value);
  195.         value = 0;
  196.       }
  197.  
  198.       if (gs.fColor)
  199.         value |= (dword)FBmGet(gi.bm, x, y) << ((x & 7 ^ 1) << 2);
  200.  
  201.       else
  202.         if (FBmGet(gi.bm, x, y))
  203.           value |= (dword)1 << (x & 31 ^ 7);
  204.     }
  205.     PutLong(value);
  206.   }
  207. }
  208.  
  209.  
  210. /* Begin the work of creating a graphics file. Prompt for a filename if */
  211. /* need be, and if valid, create the file and open it for writing.      */
  212.  
  213. void BeginFileX()
  214. {
  215.   char line[cchSzDef];
  216.  
  217.   if (gi.szFileOut == NULL && (
  218. #ifdef PS
  219. gi.fEps ||
  220. #endif
  221.     gs.fMeta || (gs.fBitmap && gs.chBmpMode == 'B'))) {
  222.     sprintf(line, "(It is recommended to specify an extension of '.%s'.)\n",
  223.       gs.fBitmap ? "bmp" :
  224. #ifdef PS
  225.       (gi.fEps ? "eps" : "wmf")
  226. #else
  227.       "wmf"
  228. #endif
  229.       );
  230.     PrintSzScreen(line);
  231.   }
  232.  
  233.   loop
  234.   {
  235.     if (gi.szFileOut == NULL) 
  236.     {
  237.       sprintf(line, "Enter name of file to write %s to", gs.fBitmap ? "bitmap" : 
  238.                                                             (gs.fPS ? "PostScript" : "metafile"));
  239.       InputString(line, line);
  240.       gi.szFileOut = line;
  241.     }
  242.     gi.file = fopen(gi.szFileOut, gs.fPS ? "w" : "wb");
  243.  
  244.     if (gi.file != NULL)
  245.       break;
  246.  
  247.     else {
  248.       PrintWarning("Couldn't create output file.");
  249.       gi.szFileOut = NULL;
  250.     }
  251.   }
  252. }
  253.  
  254.  
  255. /* Finish up the work of creating a graphics file. This basically consists */
  256. /* of just calling the appropriate routine to actually write the data in   */
  257. /* memory to a file for bitmaps and metafiles, although for PostScript we  */
  258. /* just close file as we were already writing while creating the chart.    */
  259.  
  260. void EndFileX()
  261. {
  262.   char sz[cchSzDef];
  263.  
  264.   if (gs.fBitmap) 
  265.   {
  266.     if (gi.yBand) 
  267.     {
  268.       sprintf(sz, "Writing part %d of chart bitmap to file.", gi.yOffset / gi.yBand + 1);
  269.       PrintNotice(sz);
  270.     } 
  271.     else
  272.       PrintNotice("Writing chart bitmap to file.");
  273.  
  274.     if (gs.chBmpMode == 'B')
  275.       WriteBmp(gi.file);
  276.  
  277.     else if (gs.chBmpMode == 'A')
  278.       WriteAscii(gi.file);
  279.  
  280.     else
  281.       WriteXBitmap(gi.file, gi.szFileOut, gs.chBmpMode);
  282.   }
  283. #ifdef PS
  284.   else if (gs.fPS)
  285.     PsEnd();
  286. #endif
  287.  
  288. #ifdef META
  289.   else {
  290.     PrintNotice("Writing metafile to disk.");
  291.     WriteMeta(gi.file);
  292.   }
  293. #endif
  294.  
  295.   if (!gs.fBitmap || gi.yOffset == 0)
  296.   {
  297.     fclose(gi.file);
  298.     gi.yBand = 0;
  299.   }
  300. }
  301.  
  302.  
  303. #ifdef PS
  304. /*
  305. ******************************************************************************
  306. ** PostScript File Routines.
  307. ******************************************************************************
  308. */
  309.  
  310. /* Table of PostScript header alias lines used by the program. */
  311.  
  312. CONST char FAR szPsFunctions[] =
  313. "/languagelevel where{pop languagelevel}{1}ifelse\
  314.  2 lt{\n\
  315. /sf{exch findfont exch\
  316.  dup type/arraytype eq{makefont}{scalefont}ifelse setfont}bind def\n\
  317. /rf{gsave newpath\n\
  318. 4 -2 roll moveto\
  319.  dup 0 exch rlineto exch 0 rlineto neg 0 exch rlineto closepath\n\
  320. fill grestore}bind def\n\
  321. /rc{newpath\n\
  322. 4 -2 roll moveto\
  323.  dup 0 exch rlineto exch 0 rlineto neg 0 exch rlineto closepath\n\
  324. clip newpath}bind def\n\
  325. }{/sf/selectfont load def/rf/rectfill load def\
  326. /rc/rectclip load def}ifelse\n\
  327. /center{0 begin gsave dup 4 2 roll\
  328.  translate newpath 0 0 moveto\
  329.  false charpath flattenpath pathbbox\
  330.  /URy exch def/URx exch def/LLy exch def/LLx exch def\
  331.  URx LLx sub 0.5 mul LLx add neg URy LLy sub 0.5 mul LLy add neg\
  332.  0 0 moveto rmoveto\
  333.  show grestore end}bind def\n\
  334. /center load 0 4 dict put\n\
  335. /c{setrgbcolor}bind def\n\
  336. /d{moveto 0 0 rlineto}bind def\n\
  337. /l{4 2 roll moveto lineto}bind def\n\
  338. /t{lineto}bind def\n\
  339. /el{newpath matrix currentmatrix 5 1 roll translate scale\
  340.  0 0 1 0 360 arc setmatrix stroke}bind def\n";
  341.  
  342.  
  343. /* Write a command to flush the PostScript buffer. */
  344.  
  345. void PsStrokeForce()
  346. {
  347.   if (gi.cStroke > 0) {              /* render any existing path */
  348.     fprintf(gi.file, "stroke\n");
  349.     gi.cStroke = 0;
  350.     gi.xPen = -1;                    /* Invalidate PolyLine cache */
  351.   }
  352. }
  353.  
  354.  
  355. /* Indicate that a certain number of PostScript commands have been done. */
  356.  
  357. void PsStroke(n)
  358. int n;
  359. {
  360.   gi.cStroke += n;
  361.   if (gi.cStroke > 2000)    /* Whenever we reach a certain limit, flush. */
  362.     PsStrokeForce();
  363. }
  364.  
  365.  
  366. /* Set the type of line end to be used by PostScript commands. If linecap */
  367. /* is true, then the line ends are rounded, otherwise they are squared.   */
  368.  
  369. void PsLineCap(fLineCap)
  370. bool fLineCap;
  371. {
  372.   if (fLineCap != gi.fLineCap) {
  373.     PsStrokeForce();
  374.     fprintf(gi.file, "%d setlinecap\n", fLineCap);
  375.     gi.fLineCap = fLineCap;
  376.   }
  377. }
  378.  
  379.  
  380. /* Set the dash length to be used by PostScript line commands. */
  381.  
  382. void PsDash(dashoff)
  383. int dashoff;
  384. {
  385.   if (dashoff != gi.nDash) {
  386.     PsStrokeForce();
  387.     if (dashoff)
  388.       fprintf(gi.file, "[%d %d", PSMUL, dashoff * PSMUL);
  389.     else
  390.       fprintf(gi.file, "[");
  391.     fprintf(gi.file, "]0 setdash\n");
  392.     gi.nDash = dashoff;
  393.   }
  394. }
  395.  
  396.  
  397. /* Set a linewidth size to be used by PostScript figure primitive commands. */
  398.  
  399. void PsLineWidth(linewidth)
  400. int linewidth;
  401. {
  402.   if ((real)linewidth != gi.rLineWid) {
  403.     PsStrokeForce();
  404.     fprintf(gi.file, "%d setlinewidth\n", linewidth);
  405.     gi.rLineWid = (real)linewidth;
  406.   }
  407. }
  408.  
  409.  
  410. /* Set a system font and size to be used by PostScript text commands. */
  411.  
  412. void PsFont(psfont)
  413. int psfont;
  414. {
  415.   int z;
  416.  
  417.   if (psfont != gi.nFont && gs.fFont) {
  418.     if (psfont <= 2) {
  419.       z = psfont == 1 ? 32*PSMUL : 23*PSMUL;
  420.       fprintf(gi.file, "/Astro[%d 0 0 -%d 0 0]sf\n", z, z);
  421.     } else if (psfont == 3) {
  422.       z = 26*PSMUL;
  423.       fprintf(gi.file, "/Times-Roman[%d 0 0 -%d 0 0]sf\n", z, z);
  424.     } else {
  425.       z = 10*PSMUL;
  426.       fprintf(gi.file, "/Courier[%d 0 0 -%d 0 0]sf\n", z, z);
  427.     }
  428.     gi.nFont = psfont;
  429.   }
  430. }
  431.  
  432.  
  433. /* Prompt the user for the name of a file to write the PostScript file to */
  434. /* (if not already specified), open it, and write out file header info.   */
  435.  
  436. void PsBegin()
  437. {
  438.   fprintf(gi.file, "%%!PS-Adobe-2.0");
  439.   if (gi.fEps)
  440.     fprintf(gi.file, " EPSF-2.0");
  441.   fprintf(gi.file, "\n%%%%Title: %s\n", gi.szFileOut);
  442.   fprintf(gi.file, "%%%%Creator: %s %s\n", szAppName, szVersionCore);
  443.   fprintf(gi.file, "%%%%CreationDate: %s\n", szDateCore);
  444.  
  445.   if (gi.fEps)
  446.   {
  447.     fprintf(gi.file, "%%%%BoundingBox: 0 0 %d %d\n", gs.xWin, gs.yWin);
  448.     fprintf(gi.file, "%%%%EndComments\n");
  449.     fprintf(gi.file, "%%%%BeginSetup\n");
  450.     fprintf(gi.file, szPsFunctions, 6 * PSMUL, 6 * PSMUL);
  451.     fprintf(gi.file, "%%%%EndSetup\n");
  452.     fprintf(gi.file, "0 0 %d %d rc\n", gs.xWin, gs.yWin);
  453.   }
  454.  
  455.   else
  456.   {
  457.     fprintf(gi.file, "%%%%Pages: 1 1\n");
  458.     fprintf(gi.file, "%%%%DocumentFonts: (atend)\n");
  459.     fprintf(gi.file, "%%%%BoundingBox: %d %d %d %d\n", PSGUTTER, PSGUTTER,
  460.       (int)(gs.xInch*72.0+rRound)-PSGUTTER,
  461.       (int)(gs.yInch*72.0+rRound)-PSGUTTER);
  462.     fprintf(gi.file, "%%%%EndComments\n");
  463.     fprintf(gi.file, "%%%%BeginProcSet: common\n");
  464.     fprintf(gi.file, szPsFunctions, 6 * PSMUL, 6 * PSMUL);
  465.     fprintf(gi.file, "%%%%EndProcSet\n");
  466.     fprintf(gi.file, "%%%%Page: 1 1\n");
  467.   }
  468.  
  469.   PsFont(2);
  470.   fprintf(gi.file, "gsave\n");
  471.   PsLineWidth(gi.nPenWid/2);
  472.   gi.xPen = -1;
  473.   PrintNotice("Creating PostScript chart file.");
  474. }
  475.  
  476.  
  477. /* Write out trailing information to the PostScript file and close it. */
  478.  
  479. void PsEnd()
  480. {
  481.   PsStrokeForce();
  482.  
  483.   if (gi.fEps)
  484.     fprintf(gi.file, "%%%%EOF\n");
  485.  
  486.   else
  487.   {
  488.     fprintf(gi.file, "showpage\n");
  489.     fprintf(gi.file, "%%%%PageTrailer\n");
  490.     fprintf(gi.file, "%%%%Trailer\n");
  491.     fprintf(gi.file, "%%%%DocumentFonts: Times-Roman\n");
  492.     if (gs.fFont) {
  493.       fprintf(gi.file, "%%%%+ Courier\n");
  494.       fprintf(gi.file, "%%%%+ Astro\n");
  495.     }
  496.   }
  497.   fclose(gi.file);
  498. }
  499. #endif /* PS */
  500.  
  501.  
  502. #ifdef META
  503. /*
  504. ******************************************************************************
  505. ** Metafile Routines.
  506. ******************************************************************************
  507. */
  508.  
  509. /* Output one 16 bit or 32 bit value into the metafile buffer stream. */
  510.  
  511. void MetaWord(w)
  512. word w;
  513. {
  514.   char sz[cchSzDef];
  515.  
  516.   if ((hpbyte)gi.pwMetaCur - gi.bm >= gi.cbMeta) {
  517.     sprintf(sz, "Metafile would be more than %ld bytes.", gi.cbMeta);
  518.     PrintError(sz);
  519.     Terminate(tcFatal);
  520.   }
  521.   *gi.pwMetaCur = w;
  522.   gi.pwMetaCur++;
  523. }
  524.  
  525. void MetaLong(l)
  526. long l;
  527. {
  528.   MetaWord(WLo(l));
  529.   MetaWord(WHi(l));
  530. }
  531.  
  532.  
  533. /* Output any necessary metafile records to make the current actual     */
  534. /* settings of line color, fill color, etc, be those that we know are   */
  535. /* desired. This is generally called by the primitives routines before  */
  536. /* any figure record is actually written into a metafile. We wait until */
  537. /* the last moment before changing any settings to ensure that we don't */
  538. /* output any unnecessary records, e.g. two select colors in a row.     */
  539.  
  540. void MetaSelect()
  541. {
  542.   if (gi.kiLineDes != gi.kiLineAct) 
  543.   {
  544.     MetaSelectObject(gi.kiLineDes);
  545.     gi.kiLineAct = gi.kiLineDes;
  546.   }
  547.  
  548.   if (gi.kiFillDes != gi.kiFillAct)
  549.   {
  550.     MetaSelectObject(16*4 + gi.kiFillDes);
  551.     gi.kiFillAct = gi.kiFillDes;
  552.   }
  553.  
  554.   if (gi.nFontDes != gi.nFontAct)
  555.   {
  556.     MetaSelectObject(16*5 + gi.nFontDes);
  557.     gi.nFontAct = gi.nFontDes;
  558.   }
  559.  
  560.   if (gi.kiTextDes != gi.kiTextAct)
  561.   {
  562.     MetaTextColor(rgbbmp[gi.kiTextDes]);
  563.     gi.kiTextAct = gi.kiTextDes;
  564.   }
  565.  
  566.   if (gi.nAlignDes != gi.nAlignAct)
  567.   {
  568.     MetaTextAlign(gi.nAlignDes);
  569.     gi.nAlignAct = gi.nAlignDes;
  570.   }
  571.  
  572.   gi.xPen = -1;    /* Invalidate PolyLine cache */
  573. }
  574.  
  575.  
  576. /* Output initial metafile header information into our metafile buffer. */
  577. /* We also setup and create all pen, brush, and font objects that may   */
  578. /* possibly be used in the generation and playing of the picture.       */
  579.  
  580. void MetaInit()
  581. {
  582.   int i, j, k;
  583.  
  584.   gi.pwMetaCur = (word HFAR *)gi.bm;
  585.  
  586.   /* Placable Metaheader */
  587.  
  588.   MetaLong(0x9AC6CDD7L);
  589.   MetaWord(0);      /* Not used */
  590.   MetaWord(0); MetaWord(0);
  591.   MetaWord(gs.xWin); MetaWord(gs.yWin);
  592.   MetaWord(gs.xWin/6);                     /* Units per inch */
  593.   MetaLong(0L);     /* Not used */
  594.   MetaWord(0x9AC6 ^ 0xCDD7 ^ gs.xWin ^ gs.yWin ^ gs.xWin/6);  /* Checksum */
  595.  
  596.   /* Metaheader */
  597.  
  598.   MetaWord(1);                      /* Metafile type                    */
  599.   MetaWord(9);                      /* Size of header in words          */
  600.   MetaWord(0x300);                  /* Windows version                  */
  601.   MetaLong(0L);                     /* Size of entire metafile in words */
  602.   MetaWord(16*5+1+(gs.fFont>0)*4);  /* Number of objects in metafile    */
  603.   MetaLong(17L);                    /* Size of largest record in words  */
  604.   MetaWord(0);                      /* Not used                         */
  605.  
  606.   /* Setup */
  607.  
  608.   MetaEscape(17);
  609.   MetaLong(LFromBB('A', 's', 't', 'r'));  /* "Astr" */
  610.   MetaWord(4);                            /* Creator */
  611.   MetaLong(14L);                          /* Bytes in string */
  612.   MetaLong(LFromBB('A', 's', 't', 'r'));  /* "Astr" */
  613.   MetaLong(LFromBB('o', 'l', 'o', 'g'));  /* "olog" */
  614.   MetaLong(LFromBB(' ', '4', '.', '4'));  /* " 4.4" */
  615.   MetaWord(WFromBB('0', 0));              /* "0"    */
  616.   MetaSaveDc();
  617.   MetaWindowOrg(0, 0);
  618.   MetaWindowExt(gs.xWin, gs.yWin);
  619.   MetaBkMode(1 /* Transparent */);
  620.  
  621.   /* Colors */
  622.  
  623.   for (j = 1; j <= 4; j++)
  624.   {
  625.     for (i = 0; i < 16; i++)
  626.     {
  627.       k = j <= 1 ? gi.nPenWid : 0;
  628.       MetaCreatePen(j <= 2 ? 0 : j-2 /* PS_SOLID; PS_DASH; PS_DOT */,
  629.         k, rgbbmp[i]);
  630.     }
  631.   }
  632.  
  633.   for (i = 0; i < 16; i++) {
  634.     MetaCreateBrush(0 /* BS_SOLID */, rgbbmp[i]);
  635.   }
  636.  
  637.   MetaCreateBrush(1 /* BS_NULL */, 0L);
  638.  
  639.   /* Fonts */
  640.  
  641.   if (gs.fFont) 
  642.   {
  643.     MetaCreateFont(5, 0, -8*gi.nScale, 2 /* Symbol Charset */);
  644.     MetaWord(WFromBB(1 /* Draft */, 1 | 0x10 /* Fixed | Roman */));
  645.     MetaLong(LFromBB('W', 'i', 'n', 'g'));
  646.     MetaLong(LFromBB('d', 'i', 'n', 'g'));
  647.     MetaWord(WFromBB('s', 0));
  648.  
  649.     MetaCreateFont(8, 0, -6*gi.nScale, 0 /* Ansi Charset */);
  650.     MetaWord(WFromBB(0 /* Default */, 2 | 0x10 /* Variable | Roman */));
  651.     MetaLong(LFromBB('T', 'i', 'm', 'e'));
  652.     MetaLong(LFromBB('s', ' ', 'N', 'e'));
  653.     MetaLong(LFromBB('w', ' ', 'R', 'o'));
  654.     MetaLong(LFromBB('m', 'a', 'n', 0));
  655.  
  656.     MetaCreateFont(6, 6*METAMUL, 10*METAMUL, 0 /* Ansi Charset */);
  657.     MetaWord(WFromBB(1 /* Draft */, 1 | 0x30 /* Fixed | Modern */));
  658.     MetaLong(LFromBB('C', 'o', 'u', 'r'));
  659.     MetaLong(LFromBB('i', 'e', 'r', ' '));
  660.     MetaLong(LFromBB('N', 'e', 'w', 0));
  661.  
  662.     MetaCreateFont(8, 0, -11*gi.nScale, 0 /* Ansi Charset */);
  663.     MetaWord(WFromBB(0 /* Default */, 2 | 0 /* Variable | Don't Care */));
  664.     MetaLong(LFromBB('A', 's', 't', 'r'));
  665.     MetaLong(LFromBB('o', '-', 'S', 'e'));
  666.     MetaLong(LFromBB('m', 'i', 'B', 'o'));
  667.     MetaLong(LFromBB('l', 'd', 0, 0));
  668.   }
  669. }
  670.  
  671.  
  672. /* Output trailing records to indicate the end of the metafile and then */
  673. /* actually write out the entire buffer to the specifed file.           */
  674.  
  675. void WriteMeta(file)
  676. FILE *file;
  677. {
  678.   word HFAR *w;
  679.  
  680. #if FALSE
  681.   int i;
  682.  
  683.   for (i = 16*5+1+(gs.fFont>0)*4; i >= 0; i--) {
  684.     MetaDeleteObject(i);
  685.   }
  686. #endif
  687.  
  688.   MetaRestoreDc();
  689.   MetaRecord(3, 0);    /* End record */
  690.  
  691.   *(long HFAR *)(gi.bm + 22 + 6) = ((long)((hpbyte)gi.pwMetaCur - gi.bm) - 22) / 2;
  692.  
  693.   for (w = (word HFAR *)gi.bm; w < gi.pwMetaCur; w++) {
  694.     PutWord(*w);
  695.   }
  696. }
  697. #endif /* META */
  698.  
  699.  
  700. #ifdef MOUSE
  701. #ifdef PC
  702. /*
  703. ******************************************************************************
  704. ** Mouse Routines.
  705. ******************************************************************************
  706. */
  707.  
  708. static union REGS dosreg;
  709.  
  710.  
  711. /* Setup and initialize the PC graphics mouse, returning the number of    */
  712. /* buttons available, or zero for no mouse at all. Passed in is the pixel */
  713. /* size of the screen the mouse pointer is to be contained within.        */
  714.  
  715. int MouseInit(x, y)
  716. int x, y;
  717. {
  718.   int dx, cBtn;
  719.  
  720.   if (!gs.fMouse)
  721.     return 0;
  722.   dosreg.x.ax = 0;
  723.   int86(0x33, &dosreg, &dosreg);
  724.   if (!(gs.fMouse = dosreg.x.ax))
  725.     return 0;
  726.   cBtn = dosreg.x.bx;
  727.   dx = x - 1;
  728.   dosreg.x.ax = 7;
  729.   dosreg.x.cx = 0;
  730.   dosreg.x.dx = dx;
  731.   int86(0x33, &dosreg, &dosreg);
  732.   dx = y - 1;
  733.   dosreg.x.ax = 8;
  734.   dosreg.x.cx = 0;
  735.   dosreg.x.dx = dx;
  736.   int86(0x33, &dosreg, &dosreg);
  737.   return cBtn;
  738. }
  739.  
  740.  
  741. /* Turn on or hide the PC graphics mouse pointer. */
  742.  
  743. void MouseShow(fShow)
  744. bool fShow;
  745. {
  746.   int ax;
  747.  
  748.   if (!gs.fMouse)
  749.     return;
  750.   ax = fShow ? 1 : 2;
  751.   dosreg.x.ax = ax;
  752.   int86(0x33, &dosreg, &dosreg);
  753. }
  754.  
  755.  
  756. /* Fill out the current status of the mouse: its horizontal and vertical  */
  757. /* position, and button press status. We return false if the mouse hasn't */
  758. /* changed any from the last call (assuming that the previous values are  */
  759. /* stored in the input parameters) or if the mouse isn't active at all.   */
  760.  
  761. bool MouseStatus(x, y, btn)
  762. int *x, *y, *btn;
  763. {
  764.   int bx, cx, dx, fChange;
  765.  
  766.   if (!gs.fMouse)
  767.     return fFalse;
  768.  
  769.   dosreg.x.ax = 3;
  770.   int86(0x33, &dosreg, &dosreg);
  771.  
  772.   bx = dosreg.x.bx;
  773.   cx = dosreg.x.cx;
  774.   dx = dosreg.x.dx;
  775.  
  776.   fChange = (cx != *x || dx != *y || bx != *btn);
  777.  
  778.   *x = cx;
  779.   *y = dx;
  780.   *btn = bx;
  781.   return fChange;
  782. }
  783. #endif /* PC */
  784. #endif /* MOUSE */
  785. #endif /* GRAPH */
  786.  
  787. /* xdevice.c */
  788.